/**
 * 
 */
package com.cwnuzj.ffms.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jeff.zheng 反射的工具类
 */
public class ReflectUtils {

	/**
	 * 根据指定方法的参数去构造一个新的对象的拷贝并将他返回
	 * 
	 * @param obj
	 *            原始对象
	 * @return 新对象
	 * @throws NoSuchMethodException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws SecurityException
	 * @throws IllegalArgumentException
	 */
	@SuppressWarnings("unchecked")
	public static Object copy(Object obj) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException,
			InvocationTargetException, NoSuchMethodException {
		// 获得对象的类型
		Class classType = obj.getClass();

		// 通过默认构造方法去创建一个新的对象，getConstructor的视其参数决定调用哪个构造方法
		Object objectCopy = classType.getConstructor(new Class[] {}).newInstance(new Object[] {});

		// 获得对象的所有属性
		Field[] fields = classType.getDeclaredFields();

		for (int i = 0; i < fields.length; i++) {
			// 获取数组中对应的属性
			Field field = fields[i];

			String fieldName = field.getName();
			String stringLetter = fieldName.substring(0, 1).toUpperCase();

			// 获得相应属性的getXXX和setXXX方法名称
			String getName = "get" + stringLetter + fieldName.substring(1);
			String setName = "set" + stringLetter + fieldName.substring(1);

			// 获取相应的方法
			Method getMethod = classType.getMethod(getName, new Class[] {});
			Method setMethod = classType.getMethod(setName, new Class[] { field.getType() });

			// 调用源对象的getXXX（）方法
			Object value = getMethod.invoke(obj, new Object[] {});

			// 调用拷贝对象的setXXX（）方法
			setMethod.invoke(objectCopy, new Object[] { value });
		}

		return objectCopy;
	}

	/**
	 * 通过反射,获得定义Class时声明的父类的泛型参数的类型. 如public MyDao extends
	 * GenericHibernateDAO<My> 返回My
	 * 
	 * @param clazz
	 *            继承泛型的对象
	 * @return 返回继承泛型时声明的父类的泛型参数的类型, 如果没有声明则返回 <code>Object.class</code>
	 */
	@SuppressWarnings("unchecked")
	public static Class getSuperClassGenricType(Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型. 如public BookManager extends
	 * GenricManager<Book>
	 * 
	 * @param clazz
	 *            clazz The class to introspect
	 * @param index
	 *            the Index of the generic ddeclaration,start from 0.
	 * @return the index generic declaration, or <code>Object.class</code> if
	 *         cannot be determined
	 */
	public static Class getSuperClassGenricType(Class clazz, int index) {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[index];
	}

	@SuppressWarnings("unchecked")
	public static Field getField(Class clazz, String name) throws NoSuchFieldException {
		Field field = _getField(clazz, name);
		return field;
	}

	@SuppressWarnings("unchecked")
	private static final Field _getField(final Class clazz, final String name) throws NoSuchFieldException {
		Class cls = clazz;
		try {
			Field field = cls.getDeclaredField(name);
			return field;
		} catch (NoSuchFieldException e) {
			cls = cls.getSuperclass();
			if (null == cls) {
				throw e;
			}
			return _getField(cls, name);
		}
	}

	/**
	 * 获取对象的所有属性值
	 * 
	 * @param object
	 *            对象实例
	 * @return 属性集合
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static Map<String, Object> getObjectAllProperties(Object object) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
			IllegalAccessException, InvocationTargetException {
		Map<String, Object> map = new HashMap<String, Object>();
		if (object != null) {
			Method[] methods = object.getClass().getMethods();
			for (int i = 0, n = methods.length; i < n; i++) {
				Method method = methods[i];
				if ((method.getModifiers() & Modifier.PUBLIC) == 1 && method.getDeclaringClass() != Object.class
						&& (method.getParameterTypes() == null || method.getParameterTypes().length == 0)) {
					String property = method.getName();
					if (property.startsWith("get")) {
						property = property.substring(3);
						String lower = property.substring(0, 1).toLowerCase() + property.substring(1);
						map.put(lower, method.invoke(object, new Object[0]));
					} else if (property.startsWith("is")) {
						property = property.substring(2);
						String lower = property.substring(0, 1).toLowerCase() + property.substring(1);
						map.put(lower, method.invoke(object, new Object[0]));
					}
				}
			}
		}
		return map;
	}

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 */
	public static Field getDeclaredField(Object object, String fieldName) throws NoSuchFieldException {
		return getDeclaredField(object.getClass(), fieldName);
	}

	/**
	 * 循环向上转型,获取类的DeclaredField.
	 */
	@SuppressWarnings("unchecked")
	public static Field getDeclaredField(Class clazz, String fieldName) throws NoSuchFieldException {
		for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
			try {
				return superClass.getDeclaredField(fieldName);
			} catch (NoSuchFieldException e) {
				// Field不在当前类定义,继续向上转型
			}
		}
		throw new NoSuchFieldException("No such field: " + clazz.getName() + '.' + fieldName);
	}

	/**
	 * 直接读取对象属性值,无视private/protected修饰符,不经过getter函数.
	 */
	public static Object getFieldValueNotGetter(Object object, String fieldName) throws NoSuchFieldException {
		Field field = getDeclaredField(object, fieldName);
		if (!field.isAccessible()) {
			field.setAccessible(true);
		}

		Object result = null;
		try {
			result = field.get(object);
		} catch (IllegalAccessException e) {
		}
		return result;
	}

	/**
	 * 按Filed的类型取得Field列表.
	 */
	public static List<Field> getFieldsByType(Object object, Class type) {
		List<Field> list = new ArrayList<Field>();
		Field[] fields = object.getClass().getDeclaredFields();
		for (Field field : fields) {
			if (field.getType().isAssignableFrom(type)) {
				list.add(field);
			}
		}
		return list;
	}

	/**
	 * 按FiledName获得Field的类型.
	 */
	public static Class getPropertyType(Class type, String name) throws NoSuchFieldException {
		return getDeclaredField(type, name).getType();
	}

	/**
	 * 获得field的getter函数名称.
	 */
	public static String getGetterName(Class type, String fieldName) {
		if (type.getName().equals("boolean")) {
			return "is" + StringUtils.capitalize(fieldName);
		} else {
			return "get" + StringUtils.capitalize(fieldName);
		}
	}

	/**
	 * 获得field的getter函数,如果找不到该方法,返回null.
	 */
	public static Method getGetterMethod(Class type, String fieldName) {
		try {
			return type.getMethod(getGetterName(type, fieldName));
		} catch (NoSuchMethodException e) {
		}
		return null;
	}

	/**
	 * 获得类
	 */
	public static Class classForName(String name) throws ClassNotFoundException {
		try {
			ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
			if (contextClassLoader != null) {
				return contextClassLoader.loadClass(name);
			} else {
				return Class.forName(name);
			}
		} catch (Exception e) {
			return Class.forName(name);
		}
	}

	public static boolean isGetMethod(Method method) {
		return (method.getName().startsWith("get") && !method.getName().equals("get") || method.getName().startsWith("is") && !method.getName().equals("is"))
				&& method.getReturnType() != Void.TYPE && method.getParameterTypes().length == 0;
	}

	public static boolean isSetMethod(Method method) {
		return method.getName().startsWith("set") && !method.getName().equals("set") && method.getReturnType() == Void.TYPE
				&& method.getParameterTypes().length == 1;
	}

	/**
	 * 根据类名得到该类所申明的方法的方法名。
	 * 
	 * @param className
	 *            类名
	 * @return 所申明的方法的方法名数组
	 * @since 0.4
	 */
	public static String[] getDeclaredMethods(String className) {
		String methodNames[];
		try {
			Class c = Class.forName(className);
			Method methods[] = c.getDeclaredMethods();
			methodNames = new String[methods.length];
			for (int i = 0; i < methods.length; i++) {
				methodNames[i] = methods[i].toString();
			}
			return methodNames;
		}

		catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 通过方法名调用对象方法
	 * 
	 * @param obj
	 *            类实例
	 * @param methodName
	 *            方法名字
	 * @param argsType
	 *            参数类型类表
	 * @param args
	 *            参数列表
	 * @return Object
	 * @throws java.lang.Exception
	 */
	public static Object invoke(Object obj, String methodName, Class[] argsType, Object[] args) throws Exception {
		Method methodObj = null;
		Object valObj = null;
		methodObj = obj.getClass().getMethod(methodName, argsType);
		valObj = methodObj.invoke(obj, args);
		methodObj = null;
		methodName = null;
		argsType = null;
		args = null;
		return valObj;
	}

	/**
	 * 通过方法名调用对象方法
	 * 
	 * @param obj
	 *            类实例
	 * @param methodName
	 *            方法名字
	 * @param args
	 *            参数对象列表
	 * @return
	 * @throws java.lang.Exception
	 */
	public static Object invoke(Object obj, String methodName, Object[] args) throws Exception {
		Class[] argsType = new Class[args.length];
		for (int i = 0; i < args.length; i++) {
			argsType[i] = args[i].getClass();
		}
		return invoke(obj, methodName, argsType, args);
	}

	/**
	 * 通过方法名调用类方法
	 * 
	 * @param cls
	 *            类
	 * @param methodName
	 *            方法名字
	 * @param argsType
	 *            参数类型类表
	 * @param args
	 *            参数列表
	 * @return Object
	 * @throws java.lang.Exception
	 */
	public static Object invoke(Class cls, String methodName, Class[] argsType, Object[] args) throws Exception {
		Object invokeObj = cls.newInstance();
		return invoke(invokeObj, methodName, argsType, args);
	}

	/**
	 * 通过方法名调用对象无参数方法
	 * 
	 * @param invokeObj
	 * @param methodName
	 * @return
	 * @throws java.lang.Exception
	 */
	public static Object invoke(Object invokeObj, String methodName) throws Exception {
		return invoke(invokeObj, methodName, null, null);
	}

	/**
	 * 通过方法名获得对象中的方法
	 * 
	 * @param obj
	 * @param methodName
	 * @return Method
	 */
	public static Method getMethod(Object obj, String methodName) throws Exception {
		Method[] methods = obj.getClass().getDeclaredMethods();
		int length = methods.length;
		for (int i = 0; i < length; i++) {
			String name = methods[i].getName().trim();
			methodName = methodName.trim();
			if (name.equals(methodName)) {
				return methods[i];
			}
		}
		return null;
	}

	/**
	 * 获得对象中的所有方法
	 * 
	 * @param object
	 * @return Method[]
	 */
	public static Method[] getMethods(Object object) {
		return object.getClass().getDeclaredMethods();
	}

	/**
	 * 获得对象中的所有属性
	 * 
	 * @param object
	 * @return Field[]
	 */
	public static Field[] getFeilds(Object object) {
		return object.getClass().getDeclaredFields();
	}

	/**
	 * 获得对象中的所有字段的名称
	 * 
	 * @param object
	 * @return String[]
	 */
	public static String[] getFiledsName(Object object) {
		Field[] fields = getFeilds(object);
		int length = fields.length;
		String[] fieldsName = new String[length];
		for (int i = 0; i < length; i++) {
			fieldsName[i] = fields[i].getName();
		}
		return fieldsName;
	}

}
